/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.dx.cf.code;

import java.util.ArrayList;

import com.android.dx.rop.code.LocalItem;
import com.android.dx.rop.cst.Constant;
import com.android.dx.rop.type.Prototype;
import com.android.dx.rop.type.Type;

/**
 * Interface for machines capable of executing bytecode by acting upon a
 * {@link Frame}. A machine conceptually contains four arbitrary-value argument
 * slots, slots for several literal-value arguments, and slots for branch target
 * information.
 */
public interface Machine {

	/**
	 * Gets the effective prototype of the method that this instance is being
	 * used for. The <i>effective</i> prototype includes an initial {@code this}
	 * argument for instance methods.
	 * 
	 * @return {@code non-null;} the method prototype
	 */
	public Prototype getPrototype();

	/**
	 * Clears the regular and auxiliary arguments area.
	 */
	public void clearArgs();

	/**
	 * Pops the given number of values from the stack (of either category), and
	 * store them in the arguments area, indicating that there are now that many
	 * arguments. Also, clear the auxiliary arguments.
	 * 
	 * @param frame
	 *            {@code non-null;} frame to operate on
	 * @param count
	 *            {@code >= 0;} number of values to pop
	 */
	public void popArgs(Frame frame, int count);

	/**
	 * Pops values from the stack of the types indicated by the given
	 * {@code Prototype} (popped in reverse of the argument order, so the first
	 * prototype argument type is for the deepest element of the stack), and
	 * store them in the arguments area, indicating that there are now that many
	 * arguments. Also, clear the auxiliary arguments.
	 * 
	 * @param frame
	 *            {@code non-null;} frame to operate on
	 * @param prototype
	 *            {@code non-null;} prototype indicating arguments to pop
	 */
	public void popArgs(Frame frame, Prototype prototype);

	/**
	 * Pops a value from the stack of the indicated type, and store it in the
	 * arguments area, indicating that there are now that many arguments. Also,
	 * clear the auxiliary arguments.
	 * 
	 * @param frame
	 *            {@code non-null;} frame to operate on
	 * @param type
	 *            {@code non-null;} type of the argument
	 */
	public void popArgs(Frame frame, Type type);

	/**
	 * Pops values from the stack of the indicated types (popped in reverse
	 * argument order, so the first indicated type is for the deepest element of
	 * the stack), and store them in the arguments area, indicating that there
	 * are now that many arguments. Also, clear the auxiliary arguments.
	 * 
	 * @param frame
	 *            {@code non-null;} frame to operate on
	 * @param type1
	 *            {@code non-null;} type of the first argument
	 * @param type2
	 *            {@code non-null;} type of the second argument
	 */
	public void popArgs(Frame frame, Type type1, Type type2);

	/**
	 * Pops values from the stack of the indicated types (popped in reverse
	 * argument order, so the first indicated type is for the deepest element of
	 * the stack), and store them in the arguments area, indicating that there
	 * are now that many arguments. Also, clear the auxiliary arguments.
	 * 
	 * @param frame
	 *            {@code non-null;} frame to operate on
	 * @param type1
	 *            {@code non-null;} type of the first argument
	 * @param type2
	 *            {@code non-null;} type of the second argument
	 * @param type3
	 *            {@code non-null;} type of the third argument
	 */
	public void popArgs(Frame frame, Type type1, Type type2, Type type3);

	/**
	 * Loads the local variable with the given index as the sole argument in the
	 * arguments area. Also, clear the auxiliary arguments.
	 * 
	 * @param frame
	 *            {@code non-null;} frame to operate on
	 * @param idx
	 *            {@code >= 0;} the local variable index
	 */
	public void localArg(Frame frame, int idx);

	/**
	 * Used to specify if a loaded local variable has info in the local variable
	 * table.
	 * 
	 * @param local
	 *            {@code true} if local arg has info in local variable table
	 */
	public void localInfo(boolean local);

	/**
	 * Indicates that the salient type of this operation is as given. This
	 * differentiates between, for example, the various arithmetic opcodes,
	 * which, by the time they hit a {@code Machine} are collapsed to the
	 * {@code int} variant. (See {@link BytecodeArray#parseInstruction} for
	 * details.)
	 * 
	 * @param type
	 *            {@code non-null;} the salient type of the upcoming operation
	 */
	public void auxType(Type type);

	/**
	 * Indicates that there is an auxiliary (inline, not stack) argument of type
	 * {@code int}, with the given value.
	 * <p>
	 * <b>Note:</b> Perhaps unintuitively, the stack manipulation ops (e.g.,
	 * {@code dup} and {@code swap}) use this to indicate the result stack
	 * pattern with a straightforward hex encoding of the push order starting
	 * with least-significant nibbles getting pushed first). For example, an
	 * all-category-1 {@code dup2_x1} sets this to {@code 0x12312}, and the
	 * other form of that op sets this to {@code 0x121}.
	 * </p>
	 * <p>
	 * <b>Also Note:</b> For {@code switch*} instructions, this is used to
	 * indicate the padding value (which is only useful for verification).
	 * </p>
	 * 
	 * @param value
	 *            the argument value
	 */
	public void auxIntArg(int value);

	/**
	 * Indicates that there is an auxiliary (inline, not stack) object argument,
	 * with the value based on the given constant.
	 * <p>
	 * <b>Note:</b> Some opcodes use both {@code int} and constant auxiliary
	 * arguments.
	 * </p>
	 * 
	 * @param cst
	 *            {@code non-null;} the constant containing / referencing the
	 *            value
	 */
	public void auxCstArg(Constant cst);

	/**
	 * Indicates that there is an auxiliary (inline, not stack) argument
	 * indicating a branch target.
	 * 
	 * @param target
	 *            the argument value
	 */
	public void auxTargetArg(int target);

	/**
	 * Indicates that there is an auxiliary (inline, not stack) argument
	 * consisting of a {@code switch*} table.
	 * <p>
	 * <b>Note:</b> This is generally used in conjunction with
	 * {@link #auxIntArg} (which holds the padding).
	 * </p>
	 * 
	 * @param cases
	 *            {@code non-null;} the list of key-target pairs, plus the
	 *            default target
	 */
	public void auxSwitchArg(SwitchList cases);

	/**
	 * Indicates that there is an auxiliary (inline, not stack) argument
	 * consisting of a list of initial values for a newly created array.
	 * 
	 * @param initValues
	 *            {@code non-null;} the list of constant values to initialize
	 *            the array
	 */
	public void auxInitValues(ArrayList<Constant> initValues);

	/**
	 * Indicates that the target of this operation is the given local.
	 * 
	 * @param idx
	 *            {@code >= 0;} the local variable index
	 * @param type
	 *            {@code non-null;} the type of the local
	 * @param local
	 *            {@code null-ok;} the name and signature of the local, if known
	 */
	public void localTarget(int idx, Type type, LocalItem local);

	/**
	 * "Runs" the indicated opcode in an appropriate way, using the arguments
	 * area as appropriate, and modifying the given frame in response.
	 * 
	 * @param frame
	 *            {@code non-null;} frame to operate on
	 * @param offset
	 *            {@code >= 0;} byte offset in the method to the opcode being
	 *            run
	 * @param opcode
	 *            {@code >= 0;} the opcode to run
	 */
	public void run(Frame frame, int offset, int opcode);
}
